#ifndef __EVENTS_MANAGER_H__
#define __EVENTS_MANAGER_H__

#include <cstdint>
#include <string>
#include <map>
#include <vector>
#include <typeinfo>

#include "Events.h"
#include "SimpleSingleton.hpp"

namespace PocketSurvival
{
    class PlayerData;
    class IInventory;

    class InventoryEvent : public IInventoryEvent
    {
    private:
        std::vector<IEvent *> &m_eventVec;
    public:
        inline InventoryEvent(std::vector<IEvent *> &eventVec) : m_eventVec(eventVec) {}
        virtual bool playerDrop(ComponentPlayer *componentPlayer) override;
        virtual bool playerDrapDrop(ComponentPlayer *componentPlayer, const Vector3 &dropVelocity, IInventory *inventory, uint32_t slotIndex, uint32_t count) override;
        virtual bool playerHandleMoveItem(std::shared_ptr<PlayerData> playerData, IInventory *sourceInventory, uint32_t sourceSlotIndex, IInventory *targetInventory, int32_t targetSlotIndex, uint32_t count) override;
        virtual bool playerHandleDragDrop(std::shared_ptr<PlayerData> playerData, IInventory *sourceInventory, uint32_t sourceSlotIndex, DragMode dragMode, IInventory *targetInventory, uint32_t targetSlotIndex, bool processingOnly) override;
    };

    class SignEvent : public ISignEvent
    {
    private:
        std::vector<IEvent *> &m_eventVec;
    public:
        inline SignEvent(std::vector<IEvent *> &eventVec) : m_eventVec(eventVec) {}
        virtual bool playerTouchSign(std::shared_ptr<PlayerData> playerData, const Point3 &point) override;
        virtual bool playerEditSign(std::shared_ptr<PlayerData> playerData, SignTextData &signTextData) override;
    };



    class InventoryOpenEvent : public IInventoryOpenEvent
    {
    private:
        std::vector<IEvent *> &m_eventVec;
    public:
        inline InventoryOpenEvent(std::vector<IEvent *> &eventVec) : m_eventVec(eventVec) {}
        virtual bool openInventory(std::shared_ptr<PlayerData> playerData, IInventory *inventory) override;
        virtual bool openPointInventory(std::shared_ptr<PlayerData> playerData, const Point3 &point, IInventory *inventory) override;
    };


    class PlayerEvent : public IPlayerEvent
    {
    private:
        std::vector<IEvent *> &m_eventVec;
    public:
        inline PlayerEvent(std::vector<IEvent *> &eventVec) : m_eventVec(eventVec) {}
        virtual bool cmdFrontMessage(std::shared_ptr<PlayerData> playerData, std::string &message, std::vector<uint8_t> &toClients) override;
        virtual bool message(std::shared_ptr<PlayerData> playerData, std::string &message, std::vector<uint8_t> &toClients) override;
        virtual bool playerMove(std::shared_ptr<PlayerData> playerData, const Vector3 &position) override;
        virtual bool playerPlaceBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t placeBlockValue) override;
        virtual bool playerBreakBlock(ComponentPlayer *componentPlayer, const Point3 &point, int32_t digBlockValue, int32_t toolLevel) override;
        virtual void playerRestart(ComponentPlayer* componentPlayer) override;
        virtual bool onUse(ComponentMiner *componentMiner, const Ray3& ray) override;
        virtual bool onAim(ComponentMiner *componentMiner, const Ray3& ray, AimState state) override;
    };

    class CreatureEvent : public ICreatureEvent
    {
    private:
        std::vector<IEvent *> &m_eventVec;
    public:
        inline CreatureEvent(std::vector<IEvent *> &eventVec) : m_eventVec(eventVec) {}
        virtual bool hitBody(ComponentAttacker* attacker, ComponentBody *body, const Vector3 &hitPosition, const Vector3 &hitDirection) override;
        virtual bool injureEntity(ComponentHealth *health, float amount, entt::entity attackerEntity, bool realInjure, const std::string &cause, InjureType injureType) override;
        virtual bool entityDeath(ComponentHealth *health, float amount, entt::entity attackerEntity, const std::string &cause) override;
        virtual bool dropAllItems(entt::entity entity) override;
        virtual void realTimePosition(ComponentBody *body) override;
    };


    class EventManager : public SimpleSingletonItem
    {
        friend class SimpleSingleton;
    private:
        std::map<size_t, std::vector<IEvent *>> m_eventMap;

    private:
        EventManager();
        ~EventManager();
        EventManager(const EventManager &) = delete;
        EventManager(EventManager &&) = delete;
        EventManager &operator=(const EventManager &) = delete;
        EventManager &operator=(EventManager &&) = delete;

    public:
        InventoryEvent *inventoryEvent = nullptr;
        SignEvent *signEvent = nullptr;
        InventoryOpenEvent *inventoryOpenEvent = nullptr;
        PlayerEvent *playerEvent = nullptr;
        CreatureEvent *creatureEvent = nullptr;

        template<class TEvent>
        inline void addEvent(TEvent *event)
        {
            const std::type_info &info = typeid(TEvent);
            m_eventMap[info.hash_code()].push_back(event);
        }    

    };

} // namespace PocketSurvival


#endif
